import Head from 'next/head';
import TableOptionsTable from '../../../components/prop-tables/TableOptionsTable';
import ColumnOptionsTable from '../../../components/prop-tables/ColumnOptionsTable';
import StateOptionsTable from '../../../components/prop-tables/StateOptionsTable';
import EditingCrudExamples from '../../../example-groups/EditingCRUDExamples';

<Head>
  <title>{'Editing Guide - Material React Table V3 Docs'}</title>
  <meta
    name="description"
    content="How to enable data editing features in Material React Table"
  />
</Head>

## Editing Feature Guide

If your tables need full CRUD functionality, you can enable editing features in Material React Table.

There are five visually distinct editing modes to choose from, whether you want to let users [edit data in a modal](#modal-edit-display-mode), [inline one row at a time](#row-edit-display-mode), [one cell at a time](#cell-edit-display-mode), or just always have [editing enabled for every cell](#table-edit-display-mode), or a [completely custom editing UI](#custom-edit-display-mode).

### Relevant Table Options

<TableOptionsTable
  onlyOptions={
    new Set([
      'createDisplayMode',
      'editDisplayMode',
      'enableEditing',
      'muiEditRowDialogProps',
      'muiEditTextFieldProps',
      'onCreatingRowCancel',
      'onCreatingRowChange',
      'onCreatingRowSave',
      'onEditingCellChange',
      'onEditingRowCancel',
      'onEditingRowChange',
      'onEditingRowSave',
      'positionCreatingRow',
      'renderCreateRowDialogContent',
      'renderEditRowDialogContent',
    ])
  }
/>

### Relevant Column Options

<ColumnOptionsTable
  onlyOptions={
    new Set([
      'Edit',
      'editSelectOptions',
      'editVariant',
      'enableEditing',
      'muiEditTextFieldProps',
    ])
  }
/>

### Relevant State Options

<StateOptionsTable
  onlyOptions={new Set(['editingCell', 'editingRow', 'creatingRow'])}
/>

### Enable Editing

To enable editing, you first need to set the `enableEditing` table option to `true`.

```jsx
const table = useMaterialReactTable({
  columns,
  data,
  enableEditing: true,
});
```

However, this is just the first step. You will need to hook up logic and event listeners, but it depends on which `editDisplayMode` you want to use.

### Disable Editing

Editing can be turned off on a per-column basis with the `enableEditing` column option.

```jsx
const columns = [
  {
    accessorKey: 'age',
    header: 'Age',
    enableEditing: false,
  },
];
```

In the modal editing mode, a disabled text field will still be rendered for columns with editing disabled, but in the row, cell, and table editing modes, normal cell values will be rendered instead of text fields.

If you want to completely remove an editing textfield from the editing modal or render the normal cell value instead, you can use the `Edit` column option to override the editing UI for that column.

```jsx
const columns = [
  {
    accessorKey: 'age',
    header: 'Age',
    enableEditing: false,
    Edit: () => null, //don't render anything in the editing modal for this column
    //or Edit: ({ cell, renderedCellValue }) => <>{renderedCellValue}</>, //render the normal cell value instead of a text field
  },
];
```

### Edit Display Modes

There are five different editDisplayModes to choose from. The default is `"modal"`, but you can also choose `"row"`, `"cell"`, `"table"`, or `"custom"`.

#### Modal Edit Display Mode

When using the default `"modal"` editDisplayMode, the user will be presented with a modal dialog where they can edit the data for one row at a time. No data is saved until the user clicks the save button. Clicking the cancel button clears out any changes that were made on that row.

An `onEditingRowSave` callback function prop must be provided where you will get access to the updated row data so that changes can be processed and saved. It is up to you how you handle the data. This function has a `exitEditingMode` parameter that must be called in order to exit editing mode upon save. The reason for this is so that you can perform validation checks before letting the modal close.

By default, Material React Table will render all of the cells in the row as text fields in a vertical stack. You can customize or override this behavior with the `muiEditRowDialogProps` table option, or the `renderEditRowDialogContent` table option.

```jsx
const table = useMaterialReactTable({
  columns,
  data,
  enableEditing: true,
  editDisplayMode: 'modal', //default
  onEditingRowSave: ({ table, values }) => {
    //validate data
    //save data to api
    table.setEditingRow(null); //exit editing mode
  },
  onEditingRowCancel: () => {
    //clear any validation errors
  },
  muiEditRowDialogProps: {
    //optionally customize the dialog
  },
  renderEditRowDialogContent: ({ internalEditComponents, row, table }) => {
    //optionally, completely override the render of the dialog content
    //use `internalEditComponents` to render the generated text fields, or completely render your own form and inputs
  },
});
```

#### Row Edit Display Mode

The `"row"` editDisplayMode works just like the default `"modal"` editDisplayMode, except that the editing components will render inline in the table instead of in a modal dialog. Only one row is made editable at a time.

By default, you will probably not want to save any data until the user clicks the save button, though you could wire up `onChange` or `onBlur` events to save data as the user inputs data.

```jsx
const table = useMaterialReactTable({
  columns,
  data,
  enableEditing: true,
  editDisplayMode: 'row',
  onEditingRowSave: ({ table, values }) => {
    //validate data
    //save data to api
    table.setEditingRow(null); //exit editing mode
  },
  onEditingRowCancel: () => {
    //clear any validation errors
  },
});
```

#### Cell Edit Display Mode

The `"cell"` editDisplayMode is a bit simpler visually. By default, a user can double-click a cell to activate editing mode, but only for that cell.

Then there is a bit of work for you to do to wire up either the `onBlur`, `onChange`, etc., events yourself in order to save the table data. This can be done in the `muiEditTextFieldProps` table option or column definition option.

```jsx
const columns = [
  {
    accessor: 'age',
    header: 'Age',
    muiEditTextFieldProps: ({ cell, row, table }) => ({
      onBlur: (event) => {
        //validate data
        //save data to api and/or rerender table
        // table.setEditingCell(null) is called automatically onBlur internally
      },
    }),
  },
];

const table = useMaterialReactTable({
  columns,
  data,
  enableEditing: true,
  editDisplayMode: 'cell',
  //optionally, use single-click to activate editing mode instead of default double-click
  muiTableBodyCellProps: ({ cell, column, table }) => ({
    onClick: () => {
      table.setEditingCell(cell); //set editing cell
      //optionally, focus the text field
      queueMicrotask(() => {
        const textField = table.refs.editInputRefs.current?.[column.id];
        if (textField) {
          textField.focus();
          textField.select?.();
        }
      });
    },
  }),
});
```

#### Table Edit Display Mode

The `"table"` editDisplayMode is similar to the `"cell"` editDisplayMode, but it simply has all of the data cells in the table become editable all at once. You will most likely wire up all of the logic the same way as the `"cell"` editDisplayMode.

#### Custom Edit Display Mode

There is another option if you don't like any of the built-in editDisplayModes UI. If you want to completely handle your own editing UI, you can use the `"custom"` editDisplayMode. This will give you access to the `editingCell`, `editingRow`, and `creatingRow` state options, but MRT will not render any editing UI for you. This is common for rendering a form in a sidebar or similar.

### Enable Creating

> New in V3

Material React Table offers new functionality to make creating news rows of data easier. It works just like the editing features, but with separate state options and callbacks. A Blank row is added to the table or modal for the user to fill out and submit.

#### Create Display Modes

There are just three different createDisplayModes to choose from. The default is `"modal"`, but you can also choose `"row"` or `"custom"`. They work exactly the same as their editDisplayMode counterparts.

#### Position Creating Row

> New in v2.7

By default, the creating row will be added to the top of the table. You can change this behavior with the `positionCreatingRow` table option.

```jsx
const table = useMaterialReactTable({
  columns,
  data,
  enableEditing: true,
  createDisplayMode: 'modal',
  positionCreatingRow: 'bottom', //default is 'top'
});
```

In advanced use cases, such as editing nested expanding sub-rows, you could even pass in a number to the `positionCreatingRow` table option to specify the index of the row to insert the creating row before.

#### Trigger Create Mode

To trigger a new blank row to be added to the table, we just need to just populate the `creatingRow` state option with a new blank row. This can be done with the `table.setCreatingRow` table instance API. You can either pass in `true` as an argument, or pass in row object with default values.

```jsx
const table = useMaterialReactTable({
  columns,
  data,
  enableEditing: true,
  editDisplayMode: 'modal',
  createDisplayMode: 'modal',
  onCreatingRowSave: ({ table, values }) => {
    //validate data
    //save data to api
    table.setCreatingRow(null); //exit creating mode
  },
  onCreatingRowCancel: () => {
    //clear any validation errors
  },
  renderTopToolbarCustomActions: ({ table }) => (
    <Button
      onClick={() => {
        table.setCreatingRow(true); //simplest way to open the create row modal with no default values
        //or you can pass in a row object to set default values with the `createRow` helper function
        // table.setCreatingRow(
        //   createRow(table, {
        //     //optionally pass in default values for the new row, useful for nested data or other complex scenarios
        //   }),
        // );
      }}
    >
      Create New User
    </Button>
  ),
});
```

### CRUD Examples

<EditingCrudExamples />

### Customizing Editing Components

You can pass any Material UI TextField Props with the `muiEditTextFieldProps` table option.

```jsx
const columns = [
  {
    accessor: 'age',
    header: 'Age',
    muiEditTextFieldProps: {
      required: true,
      type: 'number',
      variant: 'outlined',
    },
  },
];
```

#### Add Validation to Editing Components

You can add validation to the editing components by using the `muiEditTextFieldProps` events. You can write your validation logic and hook it up to the `onBlur`, `onChange`, etc., events, then set the `error` and `helperText` props accordingly.

If you are implementing validation, you may also need to use the `onEditingRowCancel` table option to clear the validation error state.

```jsx
const [validationErrors, setValidationErrors] = useState({});

const columns = [
  {
    accessor: 'age',
    header: 'Age',
    muiEditTextFieldProps: {
      error: !!validationErrors.age, //highlight mui text field red error color
      helperText: validationErrors.age, //show error message in helper text.
      required: true,
      type: 'number',
      onChange: (event) => {
        const value = event.target.value;
        //validation logic
        if (!value) {
          setValidationErrors((prev) => ({ ...prev, age: 'Age is required' }));
        } else if (value < 18) {
          setValidationErrors({
            ...validationErrors,
            age: 'Age must be 18 or older',
          });
        } else {
          delete validationErrors.age;
          setValidationErrors({ ...validationErrors });
        }
      },
    },
  },
];
```

### Use Custom Editing Components

If you need to use a much more complicated Editing component than the built-in textfield, you can specify a custom editing component with the `Edit` column definition option.

```tsx
const columns = [
  {
    accessorKey: 'email',
    header: 'Email',
    Edit: ({ cell, column, row, table }) => {
      const onBlur = (event) => {
        row._valuesCache[column.id] = event.target.value;
        if (isCreating) {
          setCreatingRow(row);
        } else if (isEditing) {
          setEditingRow(row);
        }
      };

      return <CustomInput onBlur={onBlur} />;
    },
  },
];
```

### Customize Actions/Edit Column

You can customize the actions column in a few different ways in the `displayColumnDefOptions` prop's `'mrt-row-actions'` section.

```jsx
const table = useMaterialReactTable({
  columns,
  data,
  displayColumnDefOptions: {
    'mrt-row-actions': {
      header: 'Edit', //change "Actions" to "Edit"
      size: 120,
      //use a text button instead of a icon button
      Cell: ({ row, table }) => (
        <Button onClick={() => table.setEditingRow(row)}>Edit Customer</Button>
      ),
    },
  },
});
```
